import sys, igraph, os, time, math, numpy, warnings
from numpy import *
warnings.simplefilter('default')
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.pyplot import figure, show
import matplotlib.dates as mdates
import matplotlib.mlab as mlab
import matplotlib.cbook as cbook

YEARS = range(2003, 2012)
REGULAR = 2
BOWL = 3
MINBOWL = 26

def fillTrueBackwards(TF, L):
    # function that does the following: ifthere is a True in the TF list then change
    # the value otherwise fill with the value behind the current value
    #last must always be true
    for i in range(len(TF)-1, -1, -1):
        if TF[i]:
            tmp = L[i]
        L[i] = tmp
    return L


def predictWin(ta, th, rank):
    # function that predicts a winner and returns the confidence and winner
    if rank[ta] == rank[th]:
        return (0, '')
    elif rank[ta] > rank[th]:
        return (rank[ta] - rank[th], ta)
    else:
        return (rank[th] - rank[ta], th)
        
def cumsum(L):
    # function that cumulatively counts all trues in a list
    ret = [1 if L[0]==True else 0]
    for i in range(1, len(L)):
        ret.append(ret[i-1] + (1 if L[i]==True else 0))           
    return ret
            

def prepareGraphs(gAll, years):
    # function that extracts regular season game graphs for every year
    gYears = []
    gDeltaScores = []
    gODScores = []
    for i, y in enumerate(years):

        #create graph for every year
        gYears.append(gAll.es.select(year_eq = y).select(type_eq = 'game').subgraph())
        gDeltaScores.append(gYears[i].es(seasonType_eq = REGULAR).subgraph())

        # the winner gets +1 delta score because else a delta of 1 maps to 0, giving problems for the
        # pagerank algorithm implementation    
        gDeltaScores[i].es['weight'] = map(lambda x: x+1, gDeltaScores[i].es['weight'])
    return (gYears, gDeltaScores)

def Main(argv):
    
    # Load Graph
    gAll = igraph.Graph.Read('ncaafb.graphml', format='graphml')
    print gAll.summary()
    (gYears, gDeltaScores) = prepareGraphs(gAll, YEARS)  

    # get measures to rank nodes
    rankers = ["g.strength(weights='weight', mode='IN')",
            "g.pagerank(weights='weight',directed=True)",
            "g.closeness(weights='weight', mode='ALL')",
            "g.neighborhood_size(order=3, mode='IN')",
            "g.neighborhood_size(order=4, mode='IN')",
            "g.neighborhood_size(order=5, mode='IN')"]
    
  
    # prepare figure and subfigures
    fig = figure()
    ax = []
    for i in range(3):
        for j in range(2):
            num = 321 + i*2 + j
            ax.append(fig.add_subplot(num))

    # for every ranker
    for i in range(len(rankers)):
            p = rankers[i]
    
            scores = []
            # for every year
            for x in range(len(YEARS)):
                # do some initializations
                y = YEARS[x]
                scores.append([])
                scores[x]=[]

                #graph for this year
                g = gDeltaScores[x]

                # calculate ranks for all nodes and store in dict
                rank = eval(p)
                rankDict = {g.vs[idx]['name']:rank[idx] for idx in range(len(rank))}

                #predict who will win the post-season bowl games
                predictwin = []
                for j, game in enumerate(gYears[x].es(seasonType_eq = BOWL)):
                    (confidence, pwin) = predictWin(game['away'], game['home'], rankDict)
                    predictwin.append((confidence, pwin, game['winner']))  

                # sort by most confident prediction first
                predictwin.sort(reverse = True)
                # put a cumulative sum of all correct predictions in a list
                pcumsum = cumsum(map(lambda (x,y,z): y==z, predictwin))
                # score is the cumulative sum of correct predictions divided by the number of games predicted
                score = map(lambda x,y: x/float(y), pcumsum, range(1, len(pcumsum)+1))
                # if games have the same rank, take all of the games with the same rank
                # ((1,1),(2,2),(3,2),(4,4)) -> ((1,1),(3,2),(4,4))
                idx = map(lambda x,y: x[0]!=y[0], predictwin[:-1], predictwin[1:])
                idx.append(True)#last one is always unique
                score = fillTrueBackwards(idx, score)
                # make sure all years have the same amount of results
                scores[x] = score[:MINBOWL]

            # average the scores for this measure/ranker over the 9 years
            scoresA = array(scores)
            means = mean(scoresA, axis=0, dtype=float64)
            stds = std(scoresA, axis=0, dtype=float64)

            # prepare variables for graphing purposes
            x = range(1,MINBOWL+1)
            y = means
            z = numpy.multiply(stds, -1)
            ymin = numpy.sum([means, z], axis=0)
            ymax = numpy.sum([means, stds], axis=0)
            
            ax[i].plot(x, y)
            ax[i].fill_between(x, ymin, ymax, alpha=0.5)
            ax[i].plot(x, [0.5 for dummy in range(len(x))], color='black', linewidth=2)
            ax[i].set_title(p)

            if i % 2 == 0:
                ax[i].set_ylabel('probability of correct prediction')
            if i > 3:
                ax[i].set_xlabel('number of games predicted')

    #show graphs
    plt.show()

    
if __name__ == "__main__":
        Main(sys.argv[1:])    
